package io.cici.cc.mybatis.plus.core;

import io.cici.cc.mybatis.lite.binding.MapperRegistry;
import io.cici.cc.mybatis.lite.executor.Executor;
import io.cici.cc.mybatis.lite.executor.keygen.KeyGenerator;
import io.cici.cc.mybatis.lite.mapping.Environment;
import io.cici.cc.mybatis.lite.mapping.MappedStatement;
import io.cici.cc.mybatis.lite.mapping.ParameterMappings;
import io.cici.cc.mybatis.lite.mapping.ResultMappings;
import io.cici.cc.mybatis.lite.parse.Node;
import io.cici.cc.mybatis.lite.session.Configuration;
import io.cici.cc.mybatis.lite.session.ExecutorType;
import io.cici.cc.mybatis.lite.session.Session;
import io.cici.cc.mybatis.lite.transaction.Transaction;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Setter
@Getter
public class MybatisConfiguration extends Configuration {


    protected final MybatisMapperRegistry mybatisMapperRegistry = new MybatisMapperRegistry(this);

    protected final Map<String, ResultMappings> resultMaps = new ConcurrentHashMap<>();
    protected final Map<String, ParameterMappings> parameterMaps = new ConcurrentHashMap<>();
    protected final Map<String, KeyGenerator> keyGenerators = new ConcurrentHashMap<>();
    protected final Map<String, Node> sqlIdToNodeMap = new ConcurrentHashMap<>();
    protected final Map<String, MappedStatement> mappedStatementIdToMappedStatementMap = new ConcurrentHashMap<>();
    /**
     * 是否生成短key缓存
     *
     * @since 3.4.0
     */
    @Setter
    @Getter
    private boolean useGeneratedShortKey = true;

    public MybatisConfiguration(Environment environment) {
        this();
        this.environment = environment;
    }

    /**
     * 初始化调用
     */
    public MybatisConfiguration() {
        super();
        this.mapUnderscoreToCamelCase = true;

    }


    @Override
    public void addMappedStatement(MappedStatement mappedStatement) {
        if (mappedStatementIdToMappedStatementMap.containsKey(mappedStatement.getId())) {
            /*
             * 说明已加载了xml中的节点； 忽略mapper中的 SqlProvider 数据
             */
            log.error("mapper[" + mappedStatement.getId() + "] is ignored, because it exists, maybe from xml file");
            return;
        }
        mappedStatementIdToMappedStatementMap.put(mappedStatement.getId(), mappedStatement);
    }

    /**
     * 使用自己的 MybatisMapperRegistry
     */
    @Override
    public MapperRegistry getMapperRegistry() {
        return mybatisMapperRegistry;
    }

    /**
     * 使用自己的 MybatisMapperRegistry
     */
    @Override
    public <T> void addMapper(Class<T> type) {
        mybatisMapperRegistry.addMapper(type);
    }

    /**
     * 使用自己的 MybatisMapperRegistry
     */
    @Override
    public void addMappers(String packageName) {
        mybatisMapperRegistry.addMappers();
    }

    /**
     * 使用自己的 MybatisMapperRegistry
     */
    @Override
    public <T> T getMapper(Class<T> type, Session session) {
        return mybatisMapperRegistry.getMapper(type, session);
    }

    /**
     * 使用自己的 MybatisMapperRegistry
     */
    @Override
    public boolean hasMapper(Class<?> type) {
        return mybatisMapperRegistry.hasMapper(type);
    }

    @Override
    public void addKeyGenerator(String id, KeyGenerator keyGenerator) {
        keyGenerators.put(id, keyGenerator);
    }

    @Override
    public Collection<String> getKeyGeneratorNames() {
        return keyGenerators.keySet();
    }

    @Override
    public Collection<KeyGenerator> getKeyGenerators() {
        return keyGenerators.values();
    }

    @Override
    public KeyGenerator getKeyGenerator(String id) {
        return keyGenerators.get(id);
    }

    @Override
    public boolean hasKeyGenerator(String id) {
        return keyGenerators.containsKey(id);
    }

    @Override
    public void addResultMap(ResultMappings rm) {
        resultMaps.put(rm.getId(), rm);

    }

    @Override
    public Collection<String> getResultMapNames() {
        return resultMaps.keySet();
    }

    @Override
    public Collection<ResultMappings> getResultMaps() {
        return resultMaps.values();
    }

    @Override
    public ResultMappings getResultMap(String id) {
        return resultMaps.get(id);
    }

    @Override
    public boolean hasResultMap(String id) {
        return resultMaps.containsKey(id);
    }

    @Override
    public void addParameterMappings(ParameterMappings pm) {
        parameterMaps.put(pm.getId(), pm);
    }

    @Override
    public Collection<String> getParameterMapNames() {
        return parameterMaps.keySet();
    }

    @Override
    public Collection<ParameterMappings> getParameterMaps() {
        return parameterMaps.values();
    }

    @Override
    public ParameterMappings getParameterMap(String id) {
        return parameterMaps.get(id);
    }

    @Override
    public boolean hasParameterMap(String id) {
        return parameterMaps.containsKey(id);
    }

    @Override
    public Map<String, Node> getSqlIdToNodeMap() {
        return sqlIdToNodeMap;
    }

    @Override
    public Collection<String> getMappedStatementNames() {

        return mappedStatementIdToMappedStatementMap.keySet();
    }

    @Override
    public Collection<MappedStatement> getMappedStatementIdToMappedStatementMap() {

        return mappedStatementIdToMappedStatementMap.values();
    }

    @Override
    public MappedStatement getMappedStatement(String id) {
        return this.getMappedStatement(id, true);
    }

    @Override
    public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {

        return mappedStatementIdToMappedStatementMap.get(id);
    }

    @Override
    public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {

        return mappedStatementIdToMappedStatementMap.containsKey(statementName);
    }

    @Override
    public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        return super.newExecutor(transaction, executorType);
    }

}
